package tedu.cn.submarine;
import javax.swing.*;
import java.awt.Graphics;
import java.util.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Timer;

public class World extends JPanel {
    private static final int RUNNING = 0;
    private static final int PAUSE = 1;
    private static final int GAME_OVER = 2;
    private static final int VICTORY = 3;
    private int state = RUNNING;

    public static final int WIDTH = 1024;
    public static final int HEIGHT = 684;

    private Battleship ship = new Battleship();
    private SeaObject[] submarines = {};
    private Mine[] mines = {};
    private Bomb[] bombs = {};
    private NuBomb[] nubombs = {};
    private ArrayList<Shield> shields = new ArrayList<>();
    private int score = 0;

    public SeaObject nextSubmarine(){
        Random rand = new Random();
        int type = rand.nextInt(20);
        if(type<10){
            return new ObserveSubmarine();
        }else if(type<15){
            return new TorpedoSubmarine();
        }else{
            return new MineSubmarine();
        }
    }

    private int shieldIndex = 0;
    public void addShield(){
        if(shields.isEmpty()){
            if(score>0&&score%100==0){
                Shield shield = ship.getShield(ship.getX(),ship.getY());
                shields.add(shield);
            }
        }else{
            if(++shieldIndex%300==0){
                shields.clear();
                shieldIndex=0;
            }
        }
    }

    private int subEnterIndex = 0;
    private int limit = 0;
    public void submarineEnterAction(){
        if(++subEnterIndex%40==0){
            if(score<100){
                SeaObject obj = nextSubmarine();
                submarines = Arrays.copyOf(submarines,submarines.length+1);
                submarines[submarines.length-1] = obj;
            }else{
                if(limit==0){
                    SeaObject obj = new NuclearSubmarine();
                    submarines = Arrays.copyOf(submarines,submarines.length+1);
                    submarines[submarines.length-1] = obj;
                    limit = 1;
                }
            }
        }
    }

    private int mineEnterIndex = 0;
    public void mineEnterAction(){
        if(++mineEnterIndex%100==0){
            for(int i=0;i<submarines.length;i++){
                SeaObject s = submarines[i];
                if(s instanceof MineSubmarine){
                    MineSubmarine ms = (MineSubmarine) s;
                    Mine m = ms.shootMine();
                    mines = Arrays.copyOf(mines,mines.length+1);
                    mines[mines.length-1] = m;
                }
            }
        }
    }

    private int nubombEnterIndex = 0;
    public void nubombEnterAction(){
        if(++nubombEnterIndex%100==0){
            for(int i=0;i<submarines.length;i++){
                SeaObject s = submarines[i];
                if(s instanceof NuclearSubmarine){
                    NuclearSubmarine ns = (NuclearSubmarine) s;
                    NuBomb n = ns.shootNuBomb();
                    nubombs = Arrays.copyOf(nubombs,nubombs.length+1);
                    nubombs[nubombs.length-1] = n;
                }
            }
        }
    }

    public void moveAction(){
        for(int i=0;i<submarines.length;i++){
            submarines[i].move();
        }
        for(int i=0;i<mines.length;i++){
            mines[i].move();
        }
        for(int i=0;i<bombs.length;i++){
            bombs[i].move();
        }
        for(int i=0;i<nubombs.length;i++){
            nubombs[i].move();
        }
        if(!shields.isEmpty()){
            for(Shield s : shields){
                s.setX(ship.getX());
            }
        }
    }

    public void outOfBoundsAction(){
        for(int i=0;i<submarines.length;i++){
            if(submarines[i].isOutOfBounds() || submarines[i].isDead()){
                submarines[i] = submarines[submarines.length-1];
                submarines = Arrays.copyOf(submarines,submarines.length-1);
            }
        }
        for(int i=0;i<mines.length;i++){
            if(mines[i].isOutOfBounds() || mines[i].isDead()){
                mines[i] = mines[mines.length-1];
                mines = Arrays.copyOf(mines,mines.length-1);
            }
        }
        for(int i=0;i<bombs.length;i++){
            if(bombs[i].isOutOfBounds() || bombs[i].isDead()){
                bombs[i] = bombs[bombs.length-1];
                bombs = Arrays.copyOf(bombs,bombs.length-1);
            }
        }
        for(int i=0;i<nubombs.length;i++){
            if(nubombs[i].isOutOfBounds() || nubombs[i].isDead()){
                nubombs[i] = nubombs[nubombs.length-1];
                nubombs = Arrays.copyOf(nubombs,nubombs.length-1);
            }
        }
    }

    public void bombBangAction(){
        for(int i=0;i< bombs.length;i++){
            Bomb b = bombs[i];
            for(int j=0;j<submarines.length;j++){
                SeaObject s = submarines[j];
                if(b.isLive() && s.isLive() && s.isHit(b)){
                    if(s instanceof NuclearSubmarine){
                        NuclearSubmarine n = (NuclearSubmarine) s;
                        if(n.getBossLife()>=0){
                            n.subtractBossLife();
                        }else{
                            n.goDead();
                            state = VICTORY;
                        }
                    }else{
                        s.goDead();
                    }
                    b.goDead();
                    if(s instanceof EnemyScore){
                        score += ((EnemyScore) s).getScore();
                    }
                    if(s instanceof EnemyLife){
                        int num = ((EnemyLife) s).getLife();
                        ship.addLife(num);
                    }
                }
            }
        }
    }

    public void mineBangAction(){
        for(int i=0;i< mines.length;i++){
            Mine m = mines[i];
            if(!shields.isEmpty()){
                for(Shield s:shields){
                    if(m.isLive() && ship.isLive() && m.isHit(s)){
                        m.goDead();
                    }
                }
            }
            if(m.isLive() && ship.isLive() && m.isHit(ship)){
                m.goDead();
                ship.subtractLife();
            }
        }
    }

    public void nubombBangAction(){
        for(int i=0;i< nubombs.length;i++){
            NuBomb n = nubombs[i];
            if(!shields.isEmpty()){
                for(Shield s:shields){
                    if(n.isLive() && ship.isLive() && n.isHit(s)){
                        n.goDead();
                    }
                }
            }
            if(n.isLive() && ship.isLive() && n.isHit(ship)){
                n.goDead();
                ship.subtractLife();
            }
        }
    }

    public void checkGameOverAction(){
        if(ship.getLife()<=0){
            state = GAME_OVER;
        }
    }

    public void action(){
        KeyAdapter k = new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                if(e.getKeyCode() == KeyEvent.VK_P){
                    if(state==RUNNING){
                        state = PAUSE;
                    }else if(state==PAUSE){
                        state = RUNNING;
                    }
                }
                if(state==RUNNING){
                    if(e.getKeyCode() == KeyEvent.VK_SPACE){
                        Bomb obj = ship.shootBomb();
                        bombs = Arrays.copyOf(bombs,bombs.length+1);
                        bombs[bombs.length-1] = obj;
                    }
                    if(e.getKeyCode() == KeyEvent.VK_LEFT){
                        ship.moveLeft();
                    }
                    if(e.getKeyCode() == KeyEvent.VK_RIGHT){
                        ship.moveRight();
                    }
                }
            }
        };
        this.addKeyListener(k);

        Timer timer = new Timer();
        int interval = 10;
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                if(state==RUNNING){
                    submarineEnterAction();
                    mineEnterAction();
                    nubombEnterAction();
                    moveAction();
                    outOfBoundsAction();
                    bombBangAction();
                    mineBangAction();
                    nubombBangAction();
                    addShield();
                    checkGameOverAction();
                    repaint();
                }
            }
        }, interval, interval);
    }

    public void paint(Graphics g){
        Images.sea.paintIcon(null,g,0,0);
        ship.paintImage(g);
        for(int i=0;i< submarines.length;i++){
            submarines[i].paintImage(g);
        }
        for(int i=0;i< mines.length;i++){
            mines[i].paintImage(g);
        }
        for(int i=0;i< bombs.length;i++){
            bombs[i].paintImage(g);
        }
        for(int i=0;i<nubombs.length;i++){
            nubombs[i].paintImage(g);
        }
        if(!shields.isEmpty()){
            for(Shield s : shields){
                s.paintImage(g);
            }
        }

        g.drawString("SCORE: "+score,200,50);
        g.drawString("LIFE: "+ship.getLife(),400,50);

        if(state==GAME_OVER){
            Images.gameover.paintIcon(null,g,357,154);
        }

        if(state==VICTORY){
            Images.victory.paintIcon(null,g,325,142);
        }
    }

    public static void main(String[] args) {
        String filepath = "bgmusic.wav";
        musicStuff musicObject = new musicStuff();
        musicObject.playMusic(filepath);

        JFrame frame = new JFrame();
        World world = new World();
        world.setFocusable(true);
        frame.add(world);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(WIDTH+18, HEIGHT+47);
        frame.setLocationRelativeTo(null);
        frame.setResizable(false);
        frame.setVisible(true);

        world.action();
    }
}
